#ifndef GENERIC_CACHE_H
#define GENERIC_CACHE_H
#include <stdio.h>
#include <stdlib.h>
#define SIZE 30

#define MAP_ENTRY(type) typedef struct\
{\
    int key;\
    type value;\
} Entry;\

#define MAP() typedef struct\
{\
    Entry entries[SIZE];\
    int size;\
} Map;\

#define MAP_INIT(type) void type##_init();

#define MAP_INIT_FUNC(type) void type##_init(Map *map)\
{\
    map->size = 0;\
}\

#define MAP_PUT(type,entity) void type##_put(Map *map, int key, entity value);

#define MAP_PUT_FUNC(type,entity) void type##_put(Map *map, int key, entity value)\
{\
    for (int i = 0; i < map->size; i++)\
        if (map->entries[i].key == key) {\
            map->entries[i].value = value;\
            return;\
        }\
    if (map->size < SIZE)\
    {\
        map->entries[map->size].key = key;\
        map->entries[map->size].value = value;\
        map->size++;\
    } else {\
        printf("Map is full\n");\
    }\
}\

#define MAP_GET(type,entity) entity type##_get(Map *map, int key);

#define MAP_GET_FUNC(type,entity) entity type##_get(Map *map, int key)\
{\
    for (int i = 0; i < map->size; i++)\
        if (map->entries[i].key == key)\
            return map->entries[i].value;\
    return NULL;\
}\

#define MAP_KEYSET(type) void type##_keySet(Map *map, int* keys);

#define MAP_KEYSET_FUNC(type) void type##_keySet(Map *map, int* keys)\
{\
    for (int i = 0; i < map->size; i++)\
        keys[i] = map->entries[i].key;\
}\

#define MAP_VALUESET(type,entity) void type##_valueSet(Map *map, entity* values);

#define MAP_VALUESET_FUNC(type,entity) void type##_valueSet(Map *map, entity* values)\
{\
    for (int i = 0; i < map->size; i++)\
        values[i] = map->entries[i].value;\
}\

#define MAP_REMOVE(type) void type##_remove(Map *map, int key);

#define MAP_REMOVE_FUNC(type) void type##_remove(Map *map, int key)\
{\
    for (int i = 0; i < map->size; i++)\
    {\
        if (map->entries[i].key == key)\
        {\
            for (int j = i+1; j < map->size; j++)\
            {\
                map->entries[j-1].key = map->entries[j].key;\
                map->entries[j-1].value = map->entries[j].value;\
            }\
            map->size -= 1;\
        }\
    }\
}\

#define INCLUDE_MAP(type,entity) MAP_ENTRY(entity) MAP() MAP_INIT(type) MAP_PUT(type,entity) MAP_GET(type,entity) MAP_KEYSET(type) MAP_VALUESET(type,entity) MAP_REMOVE(type)
#define SOURCE_MAP(type,entity) MAP_INIT_FUNC(type)  MAP_PUT_FUNC(type,entity) MAP_GET_FUNC(type,entity) MAP_KEYSET_FUNC(type) MAP_VALUESET_FUNC(type,entity) MAP_REMOVE_FUNC(type)

#endif